/**
 * 连接管理器
 * 管理所有WebSocket客户端连接和状态
 */

const { v4: uuidv4 } = require('uuid');
const EventEmitter = require('events');
const Logger = require('../utils/logger');
const config = require('../utils/config');

class ConnectionManager extends EventEmitter {
  constructor() {
    super();
    this.connections = new Map(); // 存储所有连接 clientId -> connectionInfo
    this.userConnections = new Map(); // 用户ID到连接ID的映射 userId -> Set<clientId>
    this.logger = new Logger('ConnectionManager');
    this.heartbeatInterval = null;
    this.rateLimitMap = new Map(); // 速率限制记录
    
    this.startHeartbeat();
  }

  /**
   * 注册新连接
   */
  registerConnection(socket, request) {
    const clientId = uuidv4();
    const connectionInfo = {
      clientId,
      socket,
      userId: null,
      nickname: null,
      connectedAt: new Date(),
      lastPing: new Date(),
      isAlive: true,
      ipAddress: this.getClientIP(request),
      userAgent: request.headers['user-agent'] || 'Unknown'
    };

    this.connections.set(clientId, connectionInfo);
    
    // 设置WebSocket事件监听
    this.setupSocketListeners(socket, clientId);
    
    // 检查连接数限制
    const maxConnections = config.get('websocket.maxConnections', 1000);
    if (this.connections.size > maxConnections) {
      this.logger.warn(`连接数超过限制 (${maxConnections})，当前连接数: ${this.connections.size}`);
    }

    this.logger.info(`新连接注册`, { 
      clientId, 
      totalConnections: this.connections.size,
      ipAddress: connectionInfo.ipAddress 
    });
    
    this.emit('connection:new', { clientId, connectionInfo });
    
    return clientId;
  }

  /**
   * 设置Socket事件监听
   */
  setupSocketListeners(socket, clientId) {
    // 处理连接关闭
    socket.on('close', (code, reason) => {
      this.logger.info(`连接关闭`, { clientId, code, reason: reason.toString() });
      this.removeConnection(clientId, 'close');
    });

    // 处理连接错误
    socket.on('error', (error) => {
      this.logger.error(`连接错误`, { clientId, error: error.message });
      this.removeConnection(clientId, 'error');
    });

    // 处理pong响应
    socket.on('pong', () => {
      const connection = this.connections.get(clientId);
      if (connection) {
        connection.isAlive = true;
        connection.lastPing = new Date();
        this.logger.debug(`收到pong响应`, { clientId });
      }
    });
  }

  /**
   * 用户加入（设置用户信息）
   */
  joinUser(clientId, userId, nickname) {
    const connection = this.connections.get(clientId);
    if (!connection) {
      return { success: false, error: '连接不存在' };
    }

    // 检查昵称是否已被使用
    if (this.isNicknameInUse(nickname, clientId)) {
      return { success: false, error: '昵称已被使用' };
    }

    // 更新连接信息
    connection.userId = userId;
    connection.nickname = nickname;

    // 更新用户连接映射
    if (!this.userConnections.has(userId)) {
      this.userConnections.set(userId, new Set());
    }
    this.userConnections.get(userId).add(clientId);

    this.logger.info(`用户加入`, { clientId, userId, nickname });
    this.emit('user:join', { clientId, userId, nickname, connection });

    return { success: true };
  }

  /**
   * 用户离开
   */
  leaveUser(clientId) {
    const connection = this.connections.get(clientId);
    if (!connection || !connection.userId) {
      return { success: false, error: '用户未登录或连接不存在' };
    }

    const { userId, nickname } = connection;
    
    // 从用户连接映射中移除
    const userConnections = this.userConnections.get(userId);
    if (userConnections) {
      userConnections.delete(clientId);
      if (userConnections.size === 0) {
        this.userConnections.delete(userId);
      }
    }

    this.logger.info(`用户离开`, { clientId, userId, nickname });
    this.emit('user:leave', { clientId, userId, nickname, connection });

    return { success: true };
  }

  /**
   * 移除连接
   */
  removeConnection(clientId, reason = 'unknown') {
    const connection = this.connections.get(clientId);
    if (!connection) {
      return;
    }

    // 如果用户已登录，先处理用户离开
    if (connection.userId) {
      this.leaveUser(clientId);
    }

    // 移除连接
    this.connections.delete(clientId);
    
    // 清理速率限制记录
    this.rateLimitMap.delete(clientId);

    this.logger.info(`连接移除`, { 
      clientId, 
      reason, 
      totalConnections: this.connections.size 
    });
    
    this.emit('connection:remove', { clientId, connection, reason });
  }

  /**
   * 获取连接信息
   */
  getConnection(clientId) {
    return this.connections.get(clientId);
  }

  /**
   * 根据用户ID获取连接
   */
  getConnectionsByUserId(userId) {
    const connectionIds = this.userConnections.get(userId) || new Set();
    const connections = [];
    
    for (const clientId of connectionIds) {
      const connection = this.connections.get(clientId);
      if (connection) {
        connections.push(connection);
      }
    }
    
    return connections;
  }

  /**
   * 获取所有已登录用户
   */
  getOnlineUsers() {
    const users = [];
    const processedUsers = new Set();
    
    for (const connection of this.connections.values()) {
      if (connection.userId && connection.nickname && !processedUsers.has(connection.userId)) {
        users.push({
          userId: connection.userId,
          nickname: connection.nickname,
          connectedAt: connection.connectedAt,
          connectionCount: this.userConnections.get(connection.userId)?.size || 0
        });
        processedUsers.add(connection.userId);
      }
    }
    
    return users;
  }

  /**
   * 获取连接统计
   */
  getStats() {
    return {
      totalConnections: this.connections.size,
      authenticatedUsers: this.userConnections.size,
      onlineUsers: this.getOnlineUsers().length,
      averageConnectionTime: this.calculateAverageConnectionTime()
    };
  }

  /**
   * 检查昵称是否已被使用
   */
  isNicknameInUse(nickname, excludeClientId = null) {
    for (const [clientId, connection] of this.connections) {
      if (clientId !== excludeClientId && connection.nickname === nickname) {
        return true;
      }
    }
    return false;
  }

  /**
   * 广播消息给所有连接
   */
  broadcast(message, excludeClientId = null) {
    let sentCount = 0;
    
    for (const [clientId, connection] of this.connections) {
      if (clientId !== excludeClientId && connection.socket.readyState === 1) {
        try {
          connection.socket.send(JSON.stringify(message));
          sentCount++;
        } catch (error) {
          this.logger.error(`广播消息失败`, { clientId, error: error.message });
        }
      }
    }
    
    this.logger.debug(`广播消息`, { 
      messageType: message.type, 
      sentCount, 
      totalConnections: this.connections.size 
    });
    
    return sentCount;
  }

  /**
   * 发送消息给特定用户
   */
  sendToUser(userId, message) {
    const connections = this.getConnectionsByUserId(userId);
    let sentCount = 0;
    
    for (const connection of connections) {
      if (connection.socket.readyState === 1) {
        try {
          connection.socket.send(JSON.stringify(message));
          sentCount++;
        } catch (error) {
          this.logger.error(`发送消息失败`, { 
            clientId: connection.clientId, 
            userId, 
            error: error.message 
          });
        }
      }
    }
    
    this.logger.debug(`发送消息给用户`, { userId, sentCount });
    return sentCount;
  }

  /**
   * 发送消息给特定连接
   */
  sendToConnection(clientId, message) {
    const connection = this.connections.get(clientId);
    if (!connection) {
      return { success: false, error: '连接不存在' };
    }
    
    if (connection.socket.readyState !== 1) {
      return { success: false, error: '连接未就绪' };
    }
    
    try {
      connection.socket.send(JSON.stringify(message));
      this.logger.debug(`发送消息给连接`, { clientId, messageType: message.type });
      return { success: true };
    } catch (error) {
      this.logger.error(`发送消息失败`, { clientId, error: error.message });
      return { success: false, error: error.message };
    }
  }

  /**
   * 启动心跳检测
   */
  startHeartbeat() {
    const pingInterval = config.get('websocket.pingInterval', 30000);
    const pongTimeout = config.get('websocket.pongTimeout', 5000);
    
    this.heartbeatInterval = setInterval(() => {
      this.logger.debug(`执行心跳检测`, { totalConnections: this.connections.size });
      
      for (const [clientId, connection] of this.connections) {
        if (connection.socket.readyState === 1) {
          if (!connection.isAlive) {
            this.logger.warn(`心跳超时，断开连接`, { clientId });
            connection.socket.terminate();
            continue;
          }
          
          connection.isAlive = false;
          connection.socket.ping();
          
          // 设置pong超时
          setTimeout(() => {
            if (!connection.isAlive) {
              this.logger.warn(`Pong超时，断开连接`, { clientId });
              connection.socket.terminate();
            }
          }, pongTimeout);
        }
      }
    }, pingInterval);
    
    this.logger.info(`心跳检测已启动`, { pingInterval: `${pingInterval}ms` });
  }

  /**
   * 停止心跳检测
   */
  stopHeartbeat() {
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
      this.heartbeatInterval = null;
      this.logger.info('心跳检测已停止');
    }
  }

  /**
   * 获取客户端IP地址
   */
  getClientIP(request) {
    return request.socket.remoteAddress || 
           request.headers['x-forwarded-for']?.split(',')[0].trim() ||
           request.headers['x-real-ip'] || 
           'unknown';
  }

  /**
   * 计算平均连接时间
   */
  calculateAverageConnectionTime() {
    if (this.connections.size === 0) {
      return 0;
    }
    
    const now = new Date();
    let totalTime = 0;
    
    for (const connection of this.connections.values()) {
      totalTime += now - connection.connectedAt;
    }
    
    return Math.round(totalTime / this.connections.size / 1000); // 秒
  }

  /**
   * 获取速率限制Map
   */
  getRateLimitMap() {
    return this.rateLimitMap;
  }

  /**
   * 关闭所有连接
   */
  closeAll() {
    this.logger.info(`关闭所有连接`, { totalConnections: this.connections.size });
    
    for (const connection of this.connections.values()) {
      try {
        connection.socket.close();
      } catch (error) {
        this.logger.error(`关闭连接失败`, { 
          clientId: connection.clientId, 
          error: error.message 
        });
      }
    }
    
    this.connections.clear();
    this.userConnections.clear();
    this.rateLimitMap.clear();
    this.stopHeartbeat();
  }
}

module.exports = ConnectionManager;